package com.example.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.dto.AdminLoginDTO;
import com.example.dto.UserLoginDTO;
import com.example.dto.newPasswordDTO;
import com.example.entity.Admin;
import com.example.handlers.BaseContext;
import com.example.mapper.AdminMapper;
import com.example.service.AdminService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.service.UserService;
import com.example.utils.JwtUtil;
import com.example.vo.AdminDetailVO;
import com.example.vo.AdminLoginVO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wuyunbin
 * @since 2024-10-09
 */
@Slf4j
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private HttpServletRequest request;

    @Override
    public AdminLoginVO login(AdminLoginDTO adminLoginDTO) {
        // 使用BCrypt算法对密码进行哈希处理，并打印到日志
        log.info("加密后的密文：{}", BCrypt.hashpw(adminLoginDTO.getPassword()));

        // 条件构造器，用来构建查询条件
        LambdaQueryWrapper<Admin> Wrapper = new LambdaQueryWrapper<>();
        // 设置查询条件，要求数据库里的username与前端传进来的username相等
        Wrapper.eq(Admin::getUsername, adminLoginDTO.getUsername());
        // 调用getOne()方法，根据条件构造器查询数据库，返回Admin对象
        Admin admin = this.getOne(Wrapper);
        
        // 如果没有对应的admin对象，则抛出异常
        // 抛出异常可以立即停止当前的执行流程
        if (admin == null){
            throw new RuntimeException("用户名不存在或者密码不正确");
        }

        if(!(admin.getRole()==adminLoginDTO.getRole()))
            throw new RuntimeException("权限不足");

        // 使用BCrypt算法的checkpw()方法对用户输入的密码和数据库里密码的哈希值进行匹配
        if(!BCrypt.checkpw(adminLoginDTO.getPassword(), admin.getPassword())){
            throw new RuntimeException("用户名不存在或者密码不正确");
        }

        // Claims是一个Map集合（双列集合 Key,Value）
        // JWT（JSON Web Token)
        // Jwts.claims()：创建一个新的 Claims 对象，该对象可以用来设置JWT中的声明信息。
        Claims claims= Jwts.claims();
        // 将admin的id存放在claims中
        claims.put("id",admin.getId());
        claims.put("role",admin.getRole());
        //todo 秘钥是写死的，需要活的密钥
//        Key key= Keys.hmacShaKeyFor("12345689012345678901234567890123456890123456789012345678901234568901234567890123456789012345689012345678901234567890".getBytes(StandardCharsets.UTF_8));
        // 使用claims创建token
        String token=jwtUtil.createToken(claims);

        // 创建AdminLoginVO对象，将token存入，后端传递给前端
        AdminLoginVO adminLoginVO = new AdminLoginVO();
        adminLoginVO.setToken(token);
        return adminLoginVO;
    }

    @Override
    public AdminDetailVO detail() {
        // 从Http请求头中获取名为"Authorization"的头信息，里面存放着token
//        String token = request.getHeader("authorization");
        // 从获取到的token中移除"Bearer",只保留实际令牌部分
//        token=token.replace("Bearer ","");
        // 验证token是否有效
//        if(!jwtUtil.validateToken(token)){
//            throw new RuntimeException("token已过期");
//        }
        // 解析token，获取其中的claims（声明信息）对象
//        Claims claims=jwtUtil.parseToken(token);
        // 从claim中获取key为"id"的value，并将其转换为Integer类型
//        Integer id = claims.get("id",Integer.class);
        //todo 获取线程变量中的id变量
        Integer id = BaseContext.getCurrentId();
        Admin admin = this.getById(id);
        AdminDetailVO adminDetailVO = new AdminDetailVO();
        adminDetailVO.setUsername(admin.getUsername());
//        adminDetailVO.setUsername("admin");
        return adminDetailVO;
    }

    @Override
    public void updatePassword(newPasswordDTO newPasswordDTO) {
        String encryptedPwd = BCrypt.hashpw(newPasswordDTO.getNewPassword(), BCrypt.gensalt());
        log.info("原始密码：{} | 加密后的密文：{}", newPasswordDTO.getNewPassword(), encryptedPwd);

        Admin admin = this.getById(BaseContext.getCurrentId());
        admin.setPassword(encryptedPwd);
        this.updateById(admin);
    }
}
